﻿Imports Imdb
Imports System.Linq

Public Class Main
    Public DataFolder As String = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\MovieChecker\"
    Private DataFile As String = DataFolder & "\MovieList.xml"
    Private actionClass As New ActionClass
    Private storage As Storage
    Public Loading As Boolean = False
    Private WithEvents WatchFolderTimer As New Windows.Forms.Timer
    
    Public Sub New()
        Loading = True
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
        'set loading boolean
        Loading = True
        'load existing MovieList
        Try
            LoadData()
        Catch ex As Exception
            storage = New Storage
            storage.AutoFillData()
        End Try
        'create datasource bindings with GUI
        MovieBindingSource.DataSource = storage.Movies.OrderBy(Function(x) x.Title)
        WatchFolderScanTimeTextBox.Text = CType(storage.ScanMovieTimer / 60000, String)
        AutoScanCheckBox.Checked = storage.AutoScan
        'set moviescrollistview
        MovieScrollListView.View = View.LargeIcon
        MovieScrollListView.ArrangeIcons(ListViewAlignment.Top)
        MovieScrollListView.Scrollable = True
        MovieScrollListView.LargeImageList = New ImageList
        MovieScrollListView.Sorting = SortOrder.Ascending
        MovieScrollListView.LargeImageList.ImageSize = New Drawing.Size(100, 140)
        'set moviedatagridview
        MovieDataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None
        'load correct data
        ScanMovies()
        'add posters
        actionClass.AddPosters(storage.Movies, DataFolder)
        'add checks for seen movies
        actionClass.SeenMoviesChecks(storage.Movies, storage.SeenList)
        'add items in MovieScroller
        actionClass.MovieScrollLoadData(storage.Movies, storage.SeenList, MovieScrollListView)
        'load data into MovieBindingSource
        MovieDataGridView.DataSource = MovieBindingSource
        Try
            ' don't load in case of new Storage
            MovieDataGridView.Columns("PosterImage").Visible = False
            MovieDataGridView.Columns("PosterImageFile").Visible = False
        Catch ex As Exception
            Dim a As String = ex.Message.ToString
        End Try
        
    End Sub

    Public Sub ReloadList()
        Loading = True
        'remove duplicates
        actionClass.RemoveDuplicates(storage.Movies)
        'add posters
        actionClass.AddPosters(storage.Movies, DataFolder)
        'add items in MovieScroller
        actionClass.MovieScrollLoadData(storage.Movies, storage.SeenList, MovieScrollListView)
        
        WatchFolderListBox.DataSource = Nothing
        WatchFolderListBox.DataSource = storage.WatchFolderList

        FilterItemListBox.DataSource = Nothing
        FilterItemListBox.DataSource = storage.FilterList.ToList

        SeenListBox.DataSource = Nothing
        SeenListBox.DataSource = storage.SeenList.ToList
        
        MovieBindingSource.DataSource = storage.Movies.OrderBy(Function(x) x.Title)
        MovieDataGridView.AutoResizeColumns()

        Loading = False
        NumberOfMovies.Text = "Number of Movies: " & MovieBindingSource.Count
    End Sub

    Private Function CurrentMovie() As MovieInDB
        Dim SelectedMovie As MovieInDB = CType(MovieBindingSource.Current, MovieInDB)
        Return SelectedMovie
    End Function

    Private Sub ExitStrategy(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        ' ReloadList()
        SaveData()
    End Sub

    Private Sub ScanMovies() Handles ScanMoviesButton.Click, WatchFolderTimer.Tick
        'check for currentmovielist; delete if not found
        Dim MoviesToBeDeletedList As New List(Of MovieInDB)
        For Each movieRow In storage.Movies
            If Not IO.File.Exists(movieRow.Location) Then
                MoviesToBeDeletedList.Add(movieRow)
            End If
        Next
        For Each Movie In MoviesToBeDeletedList
            storage.Movies.Remove(Movie)
        Next
        'add movies
        For Each watchFolder As String In storage.WatchFolderList
            Dim currentMovieFileList As New HashSet(Of String)
            For Each movieInDB As MovieInDB In storage.Movies
                currentMovieFileList.Add(movieInDB.Location)
            Next
            'aggregrate movienames
            If Not watchFolder Is Nothing Then
                For Each Movie In actionClass.ScanFolder(watchFolder, storage.FilterList)
                    If Not currentMovieFileList.Contains(Movie.Value) And Not Movie.Key.ToLower.Contains("sample") Then
                        Dim newMovie As New MovieInDB
                        newMovie.Title = Movie.Key
                        newMovie.Location = Movie.Value
                        storage.Movies.Add(newMovie)
                    End If
                Next
            End If
        Next
        ReloadList()
    End Sub

    Public Sub LoadData()
        storage = storage.Load(DataFile)
    End Sub

    Public Sub SaveData()
        MovieBindingSource.EndEdit()
        storage.Save(DataFile)
    End Sub

    Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveButton.Click
        SaveData()
    End Sub

    Private Sub ListBox_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) _
                Handles WatchFolderListBox.KeyDown, FilterItemListBox.KeyDown, SeenListBox.KeyDown

        If e.KeyCode = Keys.Delete Then
            Dim lb As ListBox = CType(sender, ListBox)
            For Each itemToBeDeleted As String In lb.SelectedItems
                If lb.Name = "SeenListBox" Then
                    storage.SeenList.Remove(itemToBeDeleted)
                ElseIf lb.Name = "WatchFolderListBox" Then
                    storage.WatchFolderList.Remove(itemToBeDeleted)
                ElseIf lb.Name = "FilterItemListBox" Then
                    storage.WatchFolderList.Remove(itemToBeDeleted)
                End If
            Next
            ReloadList()
        End If
    End Sub

    Private Sub HoverInfo(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellToolTipTextNeededEventArgs) Handles MovieDataGridView.CellToolTipTextNeeded
        If e.RowIndex > 0 And e.ColumnIndex > -1 Then
            If Not MovieDataGridView.Rows(e.RowIndex).IsNewRow Then
                e.ToolTipText = MovieDataGridView.Item(MovieDataGridView.Columns("Location").Index, e.RowIndex).Value.ToString
            End If
        End If
    End Sub

    Private Sub SeenChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles MovieDataGridView.CellValueChanged
        If Not Loading Then
            If e.ColumnIndex = MovieDataGridView.Columns("Seen").Index Then
                If CType(MovieBindingSource.Current, MovieInDB).Seen = True Then
                    'set to seen
                    storage.SeenList.Add(CType(MovieBindingSource.Current, MovieInDB).Title)
                    CurrentMovie.Seen = True
                Else
                    'set unseen
                    For Each item As ListViewItem In MovieScrollListView.Items
                        If storage.SeenList.Contains(item.ImageKey) Then item.Remove()
                    Next
                End If
                'add items in MovieScroller
                actionClass.MovieScrollLoadData(storage.Movies, storage.SeenList, MovieScrollListView)
                'ReloadList()

            End If
        End If
    End Sub

    Private Sub MovieBindingSource_CurrentChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MovieBindingSource.CurrentChanged
        SplitContainer2.Panel1Collapsed = True
        If Not Loading Then
            LoadMovieInWindow(CurrentMovie)
            'movie information not in DB: look up on IMDB
            If CurrentMovie.IMDBCode Is Nothing Then
                LoadIMDBMovieInformation(CurrentMovie)
            End If
        End If
    End Sub

    Private Sub IMDBLinkLabel_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles IMDBLinkLabel.LinkClicked
        If Not IMDBLinkLabel.Text = Nothing Then
            System.Diagnostics.Process.Start(IMDBLinkLabel.Text)
        End If
    End Sub

    Private Sub MovieLinkLabel_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles MovieLinkLabel.LinkClicked
        'open movie on disk
        If Not CurrentMovie.Location Is Nothing And CurrentMovie.Location.EndsWith("avi") And IO.File.Exists(CurrentMovie.Location) Then System.Diagnostics.Process.Start(CurrentMovie.Location)
    End Sub

    Private Sub SearchMovies(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchTextBox.TextChanged
        If Not SearchTextBox.Text = "" Then
            Loading = True
            Dim SearchText As String = SearchTextBox.Text.ToLower.ToString
            Dim foundMovies As New HashSet(Of MovieInDB)
            For Each Movie As MovieInDB In storage.Movies
                If Movie.Title.ToLower.Contains(SearchText) Then
                    foundMovies.Add(Movie)
                End If
                If Movie.Year.ToString IsNot Nothing Then
                    If Movie.Year.ToString.ToLower.Contains(SearchText) And Not foundMovies.Contains(Movie) Then
                        foundMovies.Add(Movie)
                    End If
                End If
                If Movie.Genres IsNot Nothing Then
                    If Movie.Genres.ToLower.Contains(SearchText) And Not foundMovies.Contains(Movie) Then
                        foundMovies.Add(Movie)
                    End If
                End If
                If Movie.Director IsNot Nothing Then
                    If Movie.Director.ToLower.Contains(SearchText) And Not foundMovies.Contains(Movie) Then
                        foundMovies.Add(Movie)
                    End If
                End If
                If Movie.Actors IsNot Nothing Then
                    If Movie.Actors.ToLower.Contains(SearchText) And Not foundMovies.Contains(Movie) Then
                        foundMovies.Add(Movie)
                    End If
                End If
            Next
            'load data into new MovieListBindingSource
            MovieBindingSource.DataSource = foundMovies.ToList.OrderBy(Function(x) x.Title)
            Loading = False
        Else
            MovieBindingSource.DataSource = storage.Movies.OrderBy(Function(x) x.Title)
            ReloadList()
            Loading = False
        End If
    End Sub

    Private Sub AddToListButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddToListButton.Click
        If TabControl1.SelectedIndex = 0 Then
            Dim FolderBrowserDialog1 As New FolderBrowserDialog
            With FolderBrowserDialog1
                .Description = "Select new watch folder"
                If .ShowDialog = Windows.Forms.DialogResult.OK And Not .SelectedPath Is Nothing Then
                    storage.WatchFolderList.Add(.SelectedPath)
                End If
            End With
        ElseIf TabControl1.SelectedIndex = 1 Then
            Dim answer As String = InputBox("Enter new string for the filter list")
            If answer Is Nothing Then Exit Sub
            storage.FilterList.Add(answer)
        ElseIf TabControl1.SelectedIndex = 2 Then
            Dim answer As String = InputBox("Enter seen movie")
            If answer Is Nothing Then Exit Sub
            storage.SeenList.Add(answer)
        End If
        ReloadList()
    End Sub

    Private Sub AutoScanCheckBox_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles AutoScanCheckBox.CheckedChanged
        If WatchFolderTimer.Enabled Then WatchFolderTimer.Stop()
        Dim checkBox As CheckBox = CType(sender, CheckBox)
        storage.AutoScan = checkBox.Checked
        If storage.AutoScan And Not WatchFolderScanTimeTextBox.Text = "" And CType(WatchFolderScanTimeTextBox.Text, Double) > 0.9 Then
            WatchFolderTimer.Interval = CType(storage.ScanMovieTimer, Integer)
            WatchFolderTimer.Start()
        End If
    End Sub

    Private Sub WatchFolderScanTimeTextBox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles WatchFolderScanTimeTextBox.KeyPress
        Dim allowedChars As String = "0123456789,"
        If allowedChars.IndexOf(e.KeyChar) = -1 Then
            ' Invalid Character
            e.Handled = True
        End If
        If CType(WatchFolderScanTimeTextBox.Text, Double) < 0.9 Then WatchFolderScanTimeTextBox.Text = "1"
        If Not storage.ScanMovieTimer = CType(WatchFolderScanTimeTextBox.Text, Double) * 60000 Then
            'restart
            storage.ScanMovieTimer = CType(WatchFolderScanTimeTextBox.Text, Double) * 60000
            WatchFolderTimer.Interval = CType(storage.ScanMovieTimer, Integer)
            WatchFolderTimer.Start()
        Else
            storage.ScanMovieTimer = CType(WatchFolderScanTimeTextBox.Text, Double) * 60000
        End If
        e.Handled = True
    End Sub

    Private Sub LoadMovieInWindow(ByVal Movie As MovieInDB)
        'load movie in window
        lbl_title.Text = Movie.Title
        lbl_year.Text = Movie.Year.ToString
        lbl_genres.Text = Movie.Genres
        lbl_director.Text = Movie.Director
        lbl_rating.Text = Movie.Rating
        txt_plot.Text = Movie.Plot
        lbl_actors.Text = Movie.Actors
        If Movie.PosterImage IsNot DBNull.Value Then
            pictureBox1.Image = Movie.PosterImage
        Else
            pictureBox1.Image = Nothing
        End If
        IMDBLinkLabel.Text = "http://www.imdb.com/title/tt" & Movie.IMDBCode
        MovieLinkLabel.Visible = True
        If Movie.IMDBCode IsNot Nothing Then
            IMDBLinkLabel.Visible = True
            IMDBLinkLabel.Enabled = True
        Else
            IMDBLinkLabel.Visible = False
            IMDBLinkLabel.Enabled = False
        End If
        AxWindowsMediaPlayer1.URL = Movie.Location
    End Sub

    Private Sub MovieScrollListView_ItemSelectionChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.ListViewItemSelectionChangedEventArgs) Handles MovieScrollListView.ItemSelectionChanged
        Dim findTitle As String = e.Item.ImageKey
        If Not lbl_title.Text = findTitle Then
            For Each Movie As MovieInDB In storage.Movies
                If Movie.Title = findTitle Then
                    'load movie
                    LoadMovieInWindow(Movie)
                End If
            Next
        End If
    End Sub

    Private Sub MovieDataGridView_UserDeletingRow(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) Handles MovieDataGridView.UserDeletingRow
        'delete row also in underlying storage
        Dim location As String = e.Row.Cells("Location").Value.ToString
        For Each Movie As MovieInDB In storage.Movies
            If Movie.Location = location Then
                storage.Movies.Remove(Movie)
                Exit For
            End If
        Next
    End Sub

    Private Sub MovieDataGridView_DataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles MovieDataGridView.DataError
        'do nothing..
        Dim a As String = e.Exception.Message
    End Sub

    'IMDB stuff
    Private Sub LoadIMDBMovieInformation(ByVal CurrentMovie As MovieInDB)
        'show panel
        SplitContainer2.Panel1Collapsed = False
        'initiate IMDB search
        Dim IMDBClass As New IMDBClass(SplitContainer2.Panel1, CurrentMovie)
        AddHandler IMDBClass.ShowFoundMovie, AddressOf LoadMovieInWindow
        AddHandler IMDBClass.CollapsePanel, AddressOf CollapseSearchPanel
        AddHandler IMDBClass.SaveMovie, AddressOf SaveMovie
    End Sub

    Private Sub SaveMovie(ByVal movie As MovieInDB)
        'called to save a movie to the DB. Autocalled if few results found.
        Dim MovieFromDB As New MovieInDB
        For Each movieInStorage As MovieInDB In storage.Movies
            If movieInStorage.Location = movie.Location Then
                movieInStorage.Actors = movie.Actors
                movieInStorage.Director = movie.Director
                movieInStorage.Genres = movie.Genres
                movieInStorage.IMDBCode = movie.IMDBCode
                movieInStorage.Plot = movie.Plot
                movieInStorage.PosterImage = movie.PosterImage
                movieInStorage.PosterImageFile = movie.PosterImageFile
                movieInStorage.Rating = movie.Rating
                movieInStorage.Title = movie.Title
                movieInStorage.Year = movie.Year
                Exit For
            End If
        Next
        Loading = True
        MovieBindingSource.ResetBindings(False)
        Loading = False
    End Sub

    Private Sub CollapseSearchPanel()
        SplitContainer2.Panel1Collapsed = True
    End Sub

    Private Sub PosterFound(ByVal MovieFound As MovieInDB)
        If CurrentMovie.Title = MovieFound.Title Then
            pictureBox1.Image = MovieFound.PosterImage
            CurrentMovie.PosterImage = MovieFound.PosterImage
            Dim FileString As String = DataFolder & CurrentMovie.IMDBCode & ".jpg"
            If Not IO.File.Exists(FileString) Then MovieFound.PosterImage.Save(FileString, System.Drawing.Imaging.ImageFormat.Jpeg)
        End If
    End Sub
End Class
